module Main where
import Codec.FFmpeg
import System.IO
import Data.Maybe
import Codec.Picture
import Control.Concurrent 
import Control.Concurrent.STM
import Control.Monad
import System.Exit (exitSuccess)
import Control.Concurrent.STM.TChan 
import Control.Concurrent.STM.TQueue
import Data.Time.Clock 
import System.Environment
import System.Process

--import Threads (sleepMs)
--replicateM_
 
import Control.Concurrent.STM.TMVar (newEmptyTMVar, takeTMVar, putTMVar)


import qualified MyLib (someFunc)



data Node a =Node a (Node a)| NULL



-- create_container::

node_size::Node a->Int 
node_size NULL=0 
node_size (Node _ y)=1+node_size y  

push_con:: TVar (Node (Image PixelRGB8))->Image PixelRGB8->STM()
push_con tcon pic =do
  con<-readTVar tcon
  -- modifyTVar tcon (\x->Node pic NULL) 
  modifyTVar tcon (\x->Node pic x)
  -- if node_size con >=4 
  --   then    
  --     retry
  -- else
  --   modifyTVar tcon (\x->Node pic x)  

pullback_con ::TVar (Node (Image PixelRGB8))->STM ()
pullback_con tcon=modifyTVar tcon remove_con 

get_last_node::Node a-> Node a 
get_last_node NULL=NULL
get_last_node (Node x NULL)=Node x NULL
get_last_node (Node x y)=get_last_node y 

remove_con::Node a-> Node a 
remove_con NULL =NULL
remove_con (Node _ NULL)=NULL
remove_con (Node x y) =Node x (remove_con y)

-- thread1 :: IO ()
-- thread1 = putStrLn "One222222222222222222"

-- thread2 :: IO ()
-- thread2 = putStrLn "Two777777777777777"



read_video::TVar (Node (Image PixelRGB8))->IO (Maybe (Image PixelRGB8,Double))->IO ()
read_video tcon  getFrame=forever $ do
  fra<-getFrame
  if fra==Nothing then 
    do
      putStrLn "end read video"
      exitSuccess
  else 
    do
      con <- atomically $ readTVar tcon
      putStrLn$  "once:" ++  (show $ node_size con)
      atomically$ push_con tcon $ fst.fromJust $ fra   





read_many::TMVar Int->  TVar (Node (Image PixelRGB8))->IO (Maybe (Image PixelRGB8,Double))->IO ()
read_many signal tcon  getFrame= do
  ss<-atomically $ takeTMVar signal 
  fra<-getFrame
  if fra==Nothing then 
    do 
      putStrLn "end read many"
      exitSuccess
  else 
    do 
      putStrLn "read many"
      atomically $ push_con tcon $ fst.fromJust $ fra 
      atomically $ putTMVar signal 1
      --atomically $ writeTVar tcon NULL



write_video:: TVar (Node (Image PixelRGB8))->IO ()
write_video tcon=do 
  con <- atomically $ readTVar tcon 
  myfun con 
  where 
    myfun:: Node (Image PixelRGB8)->IO ()
    myfun NULL=do 
      putStrLn "write_video NULL"
      return ()
    myfun (Node x _)= do 
      putStrLn "write_video"
      writeBitmap "test.bmp" x 
      atomically $ writeTVar tcon NULL 


do_manies::Int ->IO a ->IO a
do_manies 1 x = x
do_manies n x = do 
  x 
  do_manies (n-1) x

mystest ::IO ()
mystest = do 
  initFFmpeg
  (getFrame,cleanup)<- imageReaderTime (File "bunny.mp4"):: IO (IO (Maybe (Image PixelRGB8,Double)),IO() )
  con<- newTVarIO NULL
  signal<- atomically $ newEmptyTMVar 
  atomically $ putTMVar signal 1
  read_many signal con getFrame 
  do_manies 9 $ do
      write_video con 
      forkIO $ read_many signal con getFrame  
  return ()
-- 读取视频流
-- (getFrame,cleanup)<- imageReaderTime (File "rtmp:??58.200.131.2:1935/livetv/cctv1")  

main :: IO ()
main = do
  initFFmpeg

  (getFrame,cleanup)<- imageReaderTime (File "bunny.mp4"):: IO (IO (Maybe (Image PixelRGB8,Double)),IO() )
 
      --atomically $ putTMVar signal 1 
  --   mcon<- atomically $  readTVar con
  --   write_video mcon 
  --   -- atomically$  writeTVar con NULL
  --   forkIO $ read_many con getFrame

  -- forever $ do
  --   mcon<- atomically $  readTVar con 
  --   if mcon==NULL then 
  --     return ()
  --   else return ()     

    -- fra<- getFrame
    -- if fra==Nothing then do 
    --   putStrLn "end write"
    --   exitSuccess
    -- else do
    --   writeBitmap  "test.bmp" .fst.fromJust $ fra


  -- forkIO $read_video con getFrame


  writeBitmap  "test.bmp" .fst.fromJust=<<getFrame
  -- writeBitmap  "test1.bmp" .fst.fromJust=<<getFrame
  -- writeBitmap  "test2.bmp" .fst.fromJust=<<getFrame
  -- writeBitmap  "test3.bmp" .fst.fromJust=<<getFrame
  -- writeBitmap  "test4.bmp" .fst.fromJust=<<getFrame
  -- writeBitmap  "test5.bmp" .fst.fromJust=<<getFrame
  -- writeBitmap  "test6.bmp" .fst.fromJust=<<getFrame
  -- writeBitmap  "test7.bmp" .fst.fromJust=<<getFrame
  

  -- PixelRGB8
  -- cleanup 
  putStrLn "Hello, Haskell!"
  MyLib.someFunc
  -- main2
  -- main1
  -- where 
  --   myfun :: Int->IO ()
-- 线程间的同步
main1::IO ()
main1 = do
    result <- atomically $ newEmptyTMVar 
    forkIO $ do
        -- Pretend there is some actual work to do.
        sleepMs 5
        putStrLn "Calculated result!"
        atomically $ putTMVar result 42
    putStrLn "Waiting..."
    value <- atomically $ takeTMVar result
    putStrLn ("The answer is: " ++ show value)




fill_once_video_frame::IO (Maybe (Image PixelRGB8,Double))->TQueue (Image PixelRGB8,Double )->IO Int
fill_once_video_frame  getFrame  tqueue= do
  fra<-getFrame 
  putStrLn "begin1"
  myfun fra tqueue
  where 
    myfun :: Maybe (Image PixelRGB8,Double)->TQueue (Image PixelRGB8,Double)->IO Int
    myfun Nothing _ = return (-1)
    myfun (Just x) tqueue1 = do 
      atomically $ writeTQueue tqueue1  x 
      return 1

fill_video_frame ::IO(Maybe (Image PixelRGB8,Double))->TQueue (Image PixelRGB8,Double)->IO ()
fill_video_frame getFrame tqueue = do 
  putStrLn "begin"
  re<- fill_once_video_frame getFrame tqueue  
  if re==(-1) then do 
    putStrLn "end"
    return ()
  else do 
    putStrLn "once" 
    fill_video_frame getFrame tqueue  



sleepMs::Int ->IO()
sleepMs n = threadDelay (n * 1000000)




main2:: IO ()
main2 = do  
  initFFmpeg
  (getFrame,cleanup)<- imageReaderTime (File "bunny.mp4"):: IO (IO (Maybe (Image PixelRGB8,Double)),IO() )
  signal<- atomically $ newEmptyTMVar 
  --atomically $ putTMVar signal 1
  chan<- atomically $ newTChan
  queue<- atomically $ newTQueue
 -- atomically $ writeTQueue queue 1
  -- forkIO $ do 
  --   fra<- getFrame
  --   --atomically $ writeTChan chan $ (\(Just x)->x) fra
  --   atomically $ writeTQueue queue $ (\(Just x)->x) fra 
  --   --atomically $ writeTQueue queue 1
  --   putStrLn "enddd "  
  --  fill_video_frame getFrame queue
  -- forkIO $ fill_once_video_frame getFrame queue 
  -- forkIO $ fill_video_frame getFrame queue
  putStrLn "fdsddddddddddddddddddd"

  -- putStrLn "fdsddddddddddddddddddd"
  putStrLn . show =<< getCurrentTime
  
  --putStrLn "fdsddddddddddddddddddd"
  args<-getArgs
  -- callCommand "./main"
  -- system "./main"

  putStrLn $ show args

  -- sleepMs 6
  -- forever $ do 
  --   putStrLn "cron"
  --   sleepMs 1


  --threadDelay 6000000
  -- forkIO $ do 
  --   fra<- getFrame
  --   --atomically $ writeTChan chan $ (\(Just x)->x) fra
  --   -- atomically $ writeTQueue queue $ (\(Just x)->x) fra 
  --   atomically $ writeTQueue queue 1
  --   putStrLn "enddd "  
  -- forever $ do 
  --   return ()
  --atomically $ takeTMVar signal
  putStrLn "main22"